package redis

import (
	"bluebell_qimi/dao/mysql"
	"bluebell_qimi/models"
	"github.com/go-redis/redis"
	"strconv"
	"time"
)

// 从redis中根据key来获得id的相对位置
func getIDsFromKey(key string, page, size int64) ([]string, error) {
	//2. 确定查询的索引起始点
	start := (page - 1) * size
	end := start + size - 1
	//3. ZRevRange按照分数从大到校的顺序查询指定数量的元素
	return client.ZRevRange(key, start, end).Result()
}

// 从redis中获取post_id列表
func GetPostIDsInOrder(p *models.ParamPostList) ([]string, error) {
	//从redis中获取postid
	//1. 根据用户请求中携带的order参数确定要查询的redis key
	key := getRedisKey(KeyPostTimeZSet)
	if p.Order == models.OrderScore {
		key = getRedisKey(KeyPostScoreZSet)
	}
	//返回的是value
	return getIDsFromKey(key, p.Page, p.Size)
}

// 根据postids查询每篇帖子的投赞成票的票数
func GetPostVoteData(ids []string) (data []int64, err error) {
	//时间消耗大，每次都要查询一次
	//data = make([]int64, 0, len(ids))
	//for _, id := range ids {
	//	keys := getRedisKey(KeyPostVotedZSetPF + id)
	//	//查找key中分数是1的元素的个数---->统计每篇帖子的赞成票的票数
	//	v := client.ZCount(keys, "1", "1").Val()
	//	data = append(data, v)
	//}

	//为了减少RTT，使用pipeline一次发送多条数据
	pipeline := client.Pipeline()
	for _, id := range ids {
		key := getRedisKey(KeyPostVotedZSetPF + id)
		pipeline.ZCount(key, "1", "1")
	}
	cmders, err := pipeline.Exec()
	if err != nil {
		return nil, err
	}
	data = make([]int64, 0, len(cmders))
	for _, cmder := range cmders {
		v := cmder.(*redis.IntCmd).Val()
		data = append(data, v)
	}
	//每个帖子对应的投票数以切片形式返回
	return
}

// 根据帖子id查询当前帖子的投票信息,不需要pipeline批量提交，因为只查一次
func GetPostVoteDataByID(pid int64) (int64, error) {
	key := getRedisKey(KeyPostVotedZSetPF + strconv.Itoa(int(pid)))
	intCmd := client.ZCount(key, "1", "1")
	err := intCmd.Err()
	if err == redis.Nil {
		return 0, mysql.ErrorInvalidID
	}
	count := intCmd.Val()
	return count, nil
}

// 按社区查询ids
// func GetCommunityPostIDsInOrder(p *models.ParamCommunityPostList) ([]string, error) {
func GetCommunityPostIDsInOrder(p *models.ParamPostList) ([]string, error) {
	//在社区中查找帖子，判断是按时间还是按热度
	orderKey := getRedisKey(KeyPostTimeZSet)
	if p.Order == models.OrderScore {
		orderKey = getRedisKey(KeyPostScoreZSet)
	}

	//使用zinterstore把分区的帖子set与帖子分数的zset生成一个新的zset
	//针对新的zset按之前的逻辑取数据
	//社区的key
	cKey := getRedisKey(KeyCommunitySetPF + strconv.Itoa(int(p.CommunityID)))

	//利用缓存key减少zinterstore执行的次数
	key := orderKey + strconv.Itoa(int(p.CommunityID))

	if client.Exists(key).Val() < 1 {
		//不存在，需要计算
		pipeline := client.Pipeline()
		pipeline.ZInterStore(key, redis.ZStore{
			Aggregate: "MAX",
		}, cKey, orderKey) //zinterscore计算
		pipeline.Expire(key, 60*time.Second) //设置超时时间
		_, err := pipeline.Exec()
		if err != nil {
			return nil, err
		}
	}
	//存在的话就直接根据key查询ids
	return getIDsFromKey(key, p.Page, p.Size)
}
